package com.uranus.common.VO;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.uranus.common.bean.expection.BusinessException;
import com.uranus.common.constant.IgnoreUrl;
import com.uranus.common.constant.enums.LanguageEnum;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;

@Order(-99)
@Component
public class SecurityFilter implements Filter {

    @Value("${custom.jwtToken.jwtSecret}")
    private String jwtSecret="";
    private AntPathMatcher pathMatcher = new AntPathMatcher();
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        boolean hasPermission = true;
        String path = request.getRequestURI();
        String method = request.getMethod().toUpperCase();
        parseLanguage(request);


        //OPTIONS请求直接放行
        if ("OPTIONS".equals(method)) {
            hasPermission=true;
        }
        //忽略验证的 url 可以直接放行
        for (String url : IgnoreUrl.ignoreSet) {
            if (pathMatcher.match(url, path)) {
                hasPermission = true;
                break;
            }
        }


        // 先不拦截请求
        String accessToken = parseBearerToken(request);
        if(StringUtils.hasLength(accessToken)){
            TokenUserInfo tokenUserInfo = analyzeToken(accessToken);
            if(tokenUserInfo!=null && tokenUserInfo.getUserId()>0){
                ServiceContext.getInstance().setTokenUser(tokenUserInfo);
            }
        }


//            //没有被忽略的需要登录之后使用 token 访问
//            if (!hasPermission) {
//                String accessToken = parseBearerToken(request);
//                if(StringUtils.hasLength(accessToken)){
//                    try{
//                        TokenUserInfo tokenUserInfo = analyzeToken(accessToken);
//                        if(tokenUserInfo!=null && tokenUserInfo.getUserId()>0){
//                            ServiceContext.getInstance().setTokenUser(tokenUserInfo);
//                            hasPermission=true;
//                        }
//                    }catch (Exception ex){
//                        responseException(response,401,ex.getMessage());
//                    }
//
//                }
//            }

        //通过的放行，不通过的阻止访问
        if (hasPermission) {
            chain.doFilter(request, response);
        } else {
            responseException(response,401,"无权限访问:请检查是否登录");
        }
    }

    @Override
    public void destroy() {

    }


    private  String parseBearerToken(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (bearerToken == null || bearerToken.equals("")) {
            bearerToken = request.getParameter("access_token");
        }
        if (bearerToken == null || bearerToken.equals("")) {
            return "";
        }
        if (bearerToken.contains(" ")) {
            return bearerToken.split("\\s+")[1];
        } else {
            return bearerToken;
        }
    }

    /**
     * 解析请求的语言版本
     */
    private  void parseLanguage(HttpServletRequest request) {
        String language = request.getHeader("Language");
        if (language == null || language.equals("")) {
            language = request.getParameter("language");
        }
        if(StringUtils.hasLength(language)){
            if(language.toLowerCase().trim().equals("zh-cn")){
                ServiceContext.getInstance().setLanguageEnum(LanguageEnum.zh_cn);
            }
            if(language.toLowerCase().trim().equals("en-us")){
                ServiceContext.getInstance().setLanguageEnum(LanguageEnum.en_us);
            }
        }else{
            ServiceContext.getInstance().setLanguageEnum(LanguageEnum.zh_cn);
        }
    }

    /**
     * 将token 解析成对象
     */
    private TokenUserInfo analyzeToken(String accessToken) {
        Claims body = jwtParser(accessToken);
        //判断是否已经过期
        OffsetDateTime expiration = OffsetDateTime.ofInstant(Instant.ofEpochMilli(body.getExpiration().getTime()), ZoneId.systemDefault());
        if (OffsetDateTime.now().isAfter(expiration)) {
            throw new BusinessException("登录信息已过期,请重新登录");
        }
        //没有过期就获取内容
        String userId = body.getSubject();
        TokenUserInfo tokenUserInfo=new TokenUserInfo();
        tokenUserInfo.setUserId(Integer.parseInt(userId));
        tokenUserInfo.setLoginName(body.get("loginName").toString());
        tokenUserInfo.setMobile(body.get("mobile").toString());
        tokenUserInfo.setNickName(body.get("nickName").toString());
        return tokenUserInfo;
    }

    /**
     * 验证token 是否正确
     */
    private Claims jwtParser(String token) {
        Claims body;
        try {
            body = Jwts.parser().setSigningKey(jwtSecret.getBytes("UTF-8")).parseClaimsJws(token).getBody();
        } catch (Exception e) {
            throw new BusinessException("验签失败", e);
        }
        return body;
    }

    private void responseException(HttpServletResponse response, Integer statusCode, String responseObj) {
        try {
            PrintWriter out = response.getWriter();
            response.setStatus(statusCode);
            response.setContentLength(-1);
            response.setContentType("application/json;UTF-8");
            response.setDateHeader("expires", -1);
            response.setHeader("cache-control", "no-cache");
            response.setHeader("pragram", "no-cache");
            out.write(JSON.toJSONString(Result.buildError(responseObj,null), SerializerFeature.WriteMapNullValue));
            out.flush();
            out.close();
        } catch (IOException e) {
        }
    }



}
